package get

import (
	"encoding/json"
	"errors"
	"fmt"
	"github.com/urfave/cli/v2"
	"gluenet/internal/client/util"
	"gopkg.in/yaml.v3"
	"time"
	"unicode"
)

type AgentBody struct {
	Code    int         `json:"code" yaml:"code"`
	Message string      `json:"message" yaml:"message"`
	Data    []AgentData `json:"data" yaml:"data"`
}

type AgentData struct {
	Entity           interface{} `json:"Entity" yaml:"Entity"`
	Guid             string      `json:"GUID" yaml:"GUID"`
	Platform         string      `json:"Platform" yaml:"Platform"`
	Role             string      `json:"Role" yaml:"Role"`
	HostName         string      `json:"HostName" yaml:"HostName"`
	AreaID           string      `json:"AreaID" yaml:"AreaID"`
	DetailRepoKey    string      `json:"DetailRepoKey" yaml:"DetailRepoKey"`
	DetailRepoValue  interface{} `json:"DetailRepoValue" yaml:"DetailRepoValue"`
	ConfigRepoKey    string      `json:"ConfigRepoKey" yaml:"ConfigRepoKey"`
	ConfigRepoValue  interface{} `json:"ConfigRepoValue" yaml:"ConfigRepoValue"`
	RunTimeRepoKey   string      `json:"RunTimeRepoKey" yaml:"RunTimeRepoKey"`
	RunTimeRepoValue interface{} `json:"RunTimeRepoValue" yaml:"RunTimeRepoValue"`
	RegisterTime     string      `json:"RegisterTime" yaml:"RegisterTime"`
	LastConnectTime  string      `json:"LastConnectTime" yaml:"LastConnectTime"`
	Tags             interface{} `json:"Tags" yaml:"Tags"`
}

func agent(ctx *cli.Context) error {
	body, err := util.HttpRequest("GET", cliUrl+"/apis/agent/all", nil)
	if err != nil {
		return err
	}

	err = parseAgent(ctx, body)
	//fmt.Println(string(body))
	return nil
}

func parseAgent(ctx *cli.Context, body []byte) error {
	var (
		agentBody AgentBody
		idName    string
		filetype  string
	)

	err := json.Unmarshal(body, &agentBody)
	if err != nil {
		return err
	}

	if ctx.Bool("all") {
		fmt.Printf("%-40s %-25s %-15s %-10s\n",
			"Guid", "HostName", "Platform", "Age")
		fmt.Println("---------------------------------------------------------------------------" +
			"-----------------------------------------------------")
	} else {
		idName = ctx.String("id")
		filetype = ctx.String("output")
	}

	for _, agentData := range agentBody.Data {
		if ctx.Bool("all") {
			listAgentInfo(agentData)
		} else if agentData.Guid == idName {
			var outString string
			switch filetype {
			case "yaml":
				yamlByte, _ := yaml.Marshal(agentData)
				outString = string(yamlByte)
			case "json":
				jsonByte, _ := json.Marshal(agentData)
				outString = string(jsonByte)
			default:
				err = errors.New("wrong config argument: please type \"json\" or \"yaml\"")
				return err
			}

			fmt.Print(outString)
			break
		}
	}
	return nil
}

func listAgentInfo(agentData AgentData) {
	var name []byte
	nameLen := 25

	if len(agentData.HostName) < nameLen {
		cnt := 0
		for _, c := range agentData.HostName {
			if unicode.Is(unicode.Han, c) {
				cnt++
			}
		}

		slice := make([]byte, nameLen+cnt-len(agentData.HostName))
		for k := range slice {
			slice[k] = ' '
		}
		name = append([]byte(agentData.HostName), slice...)
	}

	createTime, _ := time.Parse("2006-01-02T15:04:05Z", agentData.LastConnectTime)
	age := int(time.Now().Sub(createTime).Hours())
	var ageFmt string
	if age == 0 {
		ageFmt = "<1h"
	} else if age < 24 {
		ageFmt = fmt.Sprintf("%dh", age%24)
	} else {
		ageFmt = fmt.Sprintf("%dd %dh", age/24, age%24)
	}

	fmt.Printf("%-40s %s %-15s %-15s\n",
		agentData.Guid, string(name), agentData.Platform, ageFmt)
}
